/******************************************************************/
/* 				MOLSYSTEM						*/
/* MOLSYSTEM is like the SYSTEM TASK of MINIX				*/
/* It is a molkernel thread 							*/
/******************************************************************/

#define _MULTI_THREADED
/*---------------------- LINUX HEADERS ---------------------------*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*---------------------- MINIX HEADERS ---------------------------*/
#include "../include/minix/config.h" 	
#include "../include/minix/endpoint.h"
#include "../include/minix/com.h"
#include "../../kernel/ipc.h"	

/* #include "../../kernel/config.h" 	*/
/* #include "../../kernel/const.h" 		*/
/* #include "../../kernel/type.h" 		*/

/*---------------------- MOL HEADERS -----------------------------*/
#include "../include/mol/molminix.h"
#define MOLDBG 1
#include "../include/mol/mollib.h"

#define _SYSTEM
#include "../include/mol/molerr.h" 

/*---------------------- MOLKERNEL HEADERS -------------------------*/
#include "molproc.h"
#include "svripc.h"
#include "molsystem.h"

extern struct kproc	kproc[NR_PROCS+NR_TASKS];	/* kernel process table 		*/
extern pid_t		kpid;					/* MOL  kernel PID		*/
extern ipc_t 		ctrl_ipc;				/* Ctrl IPC struct			*/
extern char 		*copybuf_ptr;			/*  COPYIN/COPYOUT buffer pointer */

/*----------------------------------------- GLOBAL VARIABLES ---------------------------------*/
mol_proc_t  molsys;			/* MOL Process data for molkernel and ipcsvr */

#define mini_receive(from,msg) 	mnx_receive(from, msg, msp);
#define mini_send(to, msg) 		mnx_send(to, msg, msp);

/*----------------------------------------------------------*/
/*		SYSTASK THREAD FUNCTION	      */
/*----------------------------------------------------------*/
void *systask_thread(void *arg)
{
	int rcode;
	int rqst, rply, src;
	message msg;
	mol_proc_t  *msp;
	
	MOLDEBUG("SYSTASK THREAD Starting\n");

	init_systask();
    
	/* initializa the pseudo clock task		*/
	init_clock();

	msp = &molsys;

	while (TRUE) 
		{
		MOLDEBUG("Waiting Request message...\n");
	
		rcode = mini_receive(ANY, &msg);
		if( rcode != OK) 
			MOLERROR("mini_receive %d\n",rcode);

		src = msg.m_source;			
		rqst= msg.m_type;
		
		MOLDEBUG("Request received: rqst=%d\n",rqst);
		switch(rqst)
			{
			case SYS_TIMES:
				do_times(&msg);
				rply = NOTOK;
				break;
			default:
				if ( src == CLOCK)
					do_hello();
				else
					MOLPRINT("Bad request: rqst=%d\n",rqst); 
				rply = NOTOK;
			break;
			}

		if(rply == OK)
			{
OLDEBUG("srcdst=%d m_type=%d m_source=%d\n", src,msg.m_type,msg.m_source);	
			rcode =  mini_send(src, &msg);
			if ( rcode < 0 )
				MOLERROR(" mnx_send: rcode=%d\n",rcode);
			}
		}
}	

/**===========================================================================*
*                             init_systask                                    *
*===========================================================================*/
int init_systask(void)
{
	int rcode;
	mol_proc_t  *msp;
	struct sigaction new_sa;	

OLDEBUG("Initializing systask task...\n");
	msp = &molsys;

	msp->p_pid = kpid;
	strncpy(msp->p_name,"system",P_NAME_LEN);

OLDEBUG("%s: Initializing  %d IPC...\n",msp->p_name,msp->p_pid);

    /*------- initialize IPC communications to MOLKERNEL and IPCSERVER ---*/
	rcode = ipc_open(msp);
    	if(rcode != OK)
      	MOLERROR("ipc_open: error:%d \n",rcode); 

OLDEBUG("Binding to molkernel\n");
    	/*------- Register the process on MOLKERNEL---------	*/
    	rcode = mnx_bind(msp);
    	if(rcode != OK)
      	MOLERROR("mnx_bind: error:%d \n",rcode);

	/* ---- Sets Signals---------------------------------	*/						
	sigemptyset(&new_sa);			/* clears all signals */
	sigaddset(&new_sa, SIGALRM);	/* Set SIGALRM flag */

}


/*===========================================================================*
 *				do_times				     *
 *===========================================================================*/
int do_times(m_ptr)
message *m_ptr;	/* pointer to request message */
{
/* Handle sys_times().  Retrieve the accounting information. */
  struct proc *rp;
  int proc_nr, e_proc_nr;

  
// rp = proc_addr(proc_nr); CODIFICAR UNA
  m_ptr->T_USER_TIME   = 1234;
  m_ptr->T_SYSTEM_TIME = 5678;
  m_ptr->T_BOOT_TICKS = get_uptime();  

 MOLDEBUG("T_USER_TIME=%d T_SYSTEM_TIME=%d T_BOOT_TICKS=%d \n",
	m_ptr->T_USER_TIME,
	m_ptr->T_SYSTEM_TIME,
	m_ptr->T_BOOT_TICKS);
	
  return(OK);
}

/*----------------------------------------------------------*/
/*                        send_container  		*/
/*----------------------------------------------------------*/
int send_container(struct kproc *pptr, int code)
{
	int rcode;
	struct kproc *sptr;
	ipc_t *cipc;

	cipc = &ctrl_ipc;
	sptr = &kproc[NR_PROCS+SYSTEM];
	
	/* Get  the process IPC channel socket address*/
	memcpy((void *)&cipc->addr, (void*)&pptr->ctrl_addr,sizeof(struct sockaddr));
	
	/* Builds the  packet					*/
	cipc->molmsg.code = code;
	cipc->molmsg.p_nr = SYSTEM;
	cipc->molmsg.p_endpoint = _ENDPOINT(0, SYSTEM);
	cipc->molmsg.seq  = 0;
	cipc->molmsg.spid = kpid;
	cipc->molmsg.srcdst = 0;
	
	if( code != HELLO)
		memcpy((void *)&cipc->molmsg.mnxmsg, (void *)&pptr->messbuf, sizeof(message));
	
	rcode =svr_send(cipc);
	if( rcode != OK )
		MOLERROR("svr_send rcode=%d",rcode);
	return(OK);
}

/*----------------------------------------------------------*/
/*                          do_hello				*/
/* test if needs to send  a HELLO Packet		 */
/*----------------------------------------------------------*/
void do_hello(void)
{
	int i, rcode;
	struct kproc *pptr;

OLDEBUG("Hello check\n");
	for( i = 0; i < (NR_PROCS+NR_TASKS); i++)
		{
		pptr = &kproc[i];
		if( pptr->p_rts_flags != SLOT_FREE)
			{
			if( ++pptr->p_hello > MAXHELLO)
				{
				rcode = send_container(pptr, HELLO);
				if (rcode == OK)
					{
					if ( ++pptr->p_dead > MAXDEAD)
						{
						MOLPRINT("Proccess[%d]:%s is DEAD\n",pptr->p_nr, pptr->p_name);
						pptr->p_rts_flags = SLOT_FREE;
						}
					}
				}
			}
		}


}

